Field Macros

您所在的位置:网站首页 action or macro to insert exhibit pages Field Macros

Field Macros

2023-04-04 14:00| 来源: 网络整理| 查看: 265

The Anchorage

Personal website of Gregory K. Maxey, Commander USN (Retired)

Quarterdeck What's New Microsoft Word Tips Consulting Chain Locker Lucky Bag Contact Search

Do you have ad-blocking software enabled? While I respect your right to do so, your donations and the minimal advertisements on this site help to defray internet and other costs of providing this content. Please consider excluding this website from blocking or turning off the blocker while browsing this site.

Word Field Macros(A Microsoft Word Help & Tip page by Gregory K. Maxey)

DISCLAIMER/TERMS OF USE

The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.

However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.

If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!

                                     

The purpose of this Microsoft Word Tips & Microsoft Word Help page is to publish a collection of  VBA procedures (macros) useful for working with the Word field collection.

I love Word fields. They are a semi-advanced Word feature and with the exception of VBA, I think that they are the most powerful and useful feature in the application.  For more on Word fields in general, see my:  Word Fields

Technical Review

Before getting to the specific field macros, I think it is important to review a few technical issues (or perhaps quirks) associated with using VBA procedures in general and using them with the field collection in particular.

Many of you are familiar with Word's Find or Find and Replace feature. It has probably saved millions of people countless hours in document preparation and editing. Seemingly by magic it can find anything and replace it with anything else.

If you record a macro of running a Find and Replace operation and then run that macro, the magic of Find and Replace seems to have lost some of the shine.

Unlike the global scope of a native "Find and Replace" operation, a VBA procedures scope is limited to a targeted range (or more accurately a targeted storyrange).  This means that if the procedure you record is run with the document focus in the main text storyrange then only matching text in the main text storyrange is found.  If you change the document focus to say a header and run the procedure again, then matching text in the header is found.   A Word document can, in a sense, be compared to a human anatomical flip chart where the first sheet is the main text (or main storyrange), flip that over and you have a drawing layer, flip that over and you have first page headers and footers, and so on.  There are up to 16 document layers (or storyranges) in a Word 2010 document. Complicating matters further, some storyranges are linked or cascade through the document. For example the storyrange for the primary header in one document section may or may not be linked and the same as the storyrange for the primary header in another section. Additionally, the TextFrame in any shape object located in a header/footer storyranges can appear immune to VBA processing. To process a complete document using a VBA procedure (be it find and replace or some action on the field collection), you have to process and perform the operation on each storyrange,  linked storyranges, and specifically target the TextFrame of shape objects located in the header and footer storyranges.

Note: A full discussion of the issue addressed above is available at:  Using a Macro to Replace Text Wherever It Appears in a Document

Accepting the issues discussed above, my approach to employing Word field macros is to start with a "universal" procedure that will process the entire document.  With this as the starting point I can then insert calls to specific "actionable" procedures that act on the targeted fields. The basic universal procedure is provided below.

VBA Script: Copy to clipboard Public Sub UniversalFieldMacro() Dim rngStory As Word.Range Dim lngLink As Long Dim oShp As Shape lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType For Each rngStory In ActiveDocument.StoryRanges 'Iterate through all linked stories Do On Error Resume Next 'Insert call to action procedure here Select Case rngStory.StoryType Case 6, 7, 8, 9, 10, 11 If rngStory.ShapeRange.Count > 0 Then For Each oShp In rngStory.ShapeRange If oShp.TextFrame.HasText Then 'Insert call to action procedure here End If Next End If Case Else 'Do Nothing End Select On Error GoTo 0 'Get next linked story (if any) Set rngStory = rngStory.NextStoryRange Loop Until rngStory Is Nothing Next rngStory lbl_Exit: Exit Sub End Sub

See: Installing Macros for instructions on how to set up and use the macros provided in this Microsoft Word Help & Microsoft Word Tips page.

If you study the code , you should see that each stroyrange, linked storyrange and troubled shape TextFrame is processed and a Word field will have nowhere to hide.

Targeting Fields with VBA

Fields are an object and therefore a countable item in any given range.  If you pass a range containing one or more fields as an argument to a VBA procedure, you can then delete all of the fields contained in that range.

VBA Script: Copy to clipboard Sub FieldsDeleteAll(ByRef oTargetRng As Range) With oTargetRng.Fields While .Count > 0 .Item(1).Delete Wend End With lbl_Exit: Exit Sub End Sub

Combining the procedure above with the universal field macro, you can delete all fields in a document.

VBA Script: Copy to clipboard Public Sub UniversalFieldMacro() Dim rngStory As Word.Range Dim lngLink As Long Dim oShp As Shape lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType For Each rngStory In ActiveDocument.StoryRanges 'Iterate through all linked stories Do On Error Resume Next 'Call actionable procedure FieldsDeleteAll rngStory Select Case rngStory.StoryType Case 6, 7, 8, 9, 10, 11 If rngStory.ShapeRange.Count > 0 Then For Each oShp In rngStory.ShapeRange If oShp.TextFrame.HasText Then 'Call actionable procedure FieldsDeleteAll oShp.TextFrame.TextRange End If Next End If Case Else 'Do Nothing End Select On Error GoTo 0 'Get next linked story (if any) Set rngStory = rngStory.NextStoryRange Loop Until rngStory Is Nothing Next rngStory lbl_Exit: Exit Sub End Sub Sub FieldsDeleteAll(ByRef oTargetRng As Range) With oTargetRng.Fields While .Count > 0 .Item(1).Delete Wend End With lbl_Exit: Exit Sub End Sub

Perhaps you don't want to delete all fields.  You may only want to delete a particular type field.  To do this you simply create an actionable procedure targeting only a specific field (or fields)and call it using the universal macro.

VBA Script: Copy to clipboard Sub DeleteAllSpecificFields(ByRef oTargetRng As Range) Dim oFld As Word.Field For Each oFld In oTargetRng.Fields Select Case oFld.Type Case wdFieldPage oFld.Delete Case Else 'Do nothing End Select Next oFld lbl_Exit: Exit Sub End Sub

Then there is the case when you may only want to delete fields in specific storyrange (e.g., headers or footers).  It can start to get complicated, but again you can use the universal macro to call a carefully crafted actionable procedure.

VBA Script: Copy to clipboard Public Sub UniversalFieldMacro() Dim rngStory As Word.Range Dim lngLink As Long Dim oShp As Shape lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType For Each rngStory In ActiveDocument.StoryRanges 'Iterate through all linked stories Do On Error Resume Next 'Call actionable procedure 'FieldsDeleteAll rngStory 'DeleteAllSpecificFields rngStory DeleteAllSpecificFieldsInSpecifStoryRange rngStory, wdPrimaryFooterStory Select Case rngStory.StoryType Case 6, 7, 8, 9, 10, 11 If rngStory.ShapeRange.Count > 0 Then For Each oShp In rngStory.ShapeRange If oShp.TextFrame.HasText Then 'Call actionable procedure 'FieldsDeleteAll oShp.TextFrame.TextRange 'DeleteAllSpecificFields rngStory End If Next End If Case Else 'Do Nothing End Select On Error GoTo 0 'Get next linked story (if any) Set rngStory = rngStory.NextStoryRange Loop Until rngStory Is Nothing Next rngStory lbl_Exit: Exit Sub End Sub Sub DeleteAllSpecificFieldsInSpecifStoryRange(ByRef oTargetRng As Range, lngStoryType As Long) Dim oFld As Field Dim oShp As Shape Select Case oTargetRng.StoryType Case lngStoryType For Each oFld In oTargetRng.Fields Select Case oFld.Type Case wdFieldPage oFld.Delete Case Else 'Do nothing End Select Next oFld Select Case lngStoryType Case 6, 7, 8, 9, 10, 11 If oTargetRng.ShapeRange.Count > 0 Then For Each oShp In oTargetRng.ShapeRange If oShp.TextFrame.HasText Then For Each oFld In oShp.TextFrame.TextRange.Fields Select Case oFld.Type Case wdFieldPage oFld.Delete Case Else 'Do nothing End Select Next oFld End If Next oShp End If Case Else 'Do nothing End Select Case Else 'Do nothing End Select lbl_Exit: Exit Sub End Sub

In the code posted above, notice in the universal macro that the actionable procedure is only called in the main For Each rngStory ... Next loop and not repeated in the For Each oShp ... Next loop. This is because shaped (even shapes in the header and footers have their own storytype definition). Processing of the header and footer storyrange shapes is incorporated in the actionable procedure.

Special Cases:

Some Word fields themselves target a collection.  For example, the DocProperty field shown below returns the value of a targeted property "Author" in the document properties collection.

If you need to target a specific target in a specific field then you can use a customized VBA procedure to peel back another layer of the onion and look a the field code.

Given the unlikelihood that the field used in this example will be located in a shape in the header or footer, I've simplified the procedure by eliminating the code required to handle that situation.

VBA Script: Copy to clipboard Sub TargetSpecificTargetInSpecificFields() Dim rngStory As Word.Range Dim oFld As Word.Field Dim lngLink As Long lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType For Each rngStory In ActiveDocument.StoryRanges Do For Each oFld In rngStory.Fields Select Case oFld.Type Case wdFieldDocProperty 'Dig a little deeper and see what the field code contains. If InStr(oFld.Code.Text, "Author") Then oFld.Unlink End If Case Else 'Do nothing End Select Next Set rngStory = rngStory.NextStoryRange Loop Until rngStory Is Nothing Next lbl_Exit: Exit Sub End Sub General Field Action Macro

This section shows you how you can target all fields with a general actionable procedure and delete, lock, unlink, update, or unlock all fields in a document using the universal field macro.

VBA Script: Copy to clipboard Sub FieldsActionAll(ByRef oTargetRng As Range, strAction As String, Optional bLocked As Boolean = False) 'Action is passed as an argument by the calling universal field macro. 'Example calls: 1. In the For Each rngStory ... Next loop: FieldsActionAll rngStory, "Update" 2. In the For Each oShp ... Next loop: oShp.TextFrame.TextRange, "Update" Select Case strAction Case "Update" oTargetRng.Fields.Update Case "Unlink" oTargetRng.Fields.Unlink Case "Locked" 'Takes the optional argument oTargetRng.Fields.Locked = bLocked 'You can pass "Delete" too!! Case "Delete" With oTargetRng.Fields While .Count > 0 .Item(1).Delete Wend End With End Select lbl_Exit: Exit Sub End Sub

Note: You should see that the actionable procedure shown eliminates the need for a specific actionable procedure Sub FieldsDeleteAll() demonstrated earlier!!

Leverage VBA Calls & Arguements

In the previous examples you saw how the universal field macro was used to call and pass arguments to the actionable procedures.  Taking this a step further, you can call and pass arguments to the universal field macro making it the middle man for one or more field actions you may want to perform.

For example, I've assigned the keyboard shortcut F9 to the procedure FieldsUpdateAll shown below.  By revising the UniversalFieldMacro to take an argument, I can simply press F9 and all fields in my document are updated.

VBA Script: Copy to clipboard Sub FieldsUpdateAll() UniversalFieldMacro "Update" lbl_Exit: Exit Sub End Sub Public Sub UniversalFieldMacro(ByRef strAction As String) Dim rngStory As Word.Range Dim lngLink As Long Dim oShp As Shape lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType For Each rngStory In ActiveDocument.StoryRanges 'Iterate through all linked stories Do On Error Resume Next 'Call actionable procedure FieldsActionAll rngStory, strAction Select Case rngStory.StoryType Case 6, 7, 8, 9, 10, 11 If rngStory.ShapeRange.Count > 0 Then For Each oShp In rngStory.ShapeRange If oShp.TextFrame.HasText Then 'Call actionable procedure FieldsActionAll oShp.TextFrame.TextRange, strAction End If Next End If Case Else 'Do Nothing End Select On Error GoTo 0 'Get next linked story (if any) Set rngStory = rngStory.NextStoryRange Loop Until rngStory Is Nothing Next rngStory lbl_Exit: Exit Sub End Sub Other Custom Field Macros

I'll use this space to post custom field macros that I've created or found interesting.

The first is one I consider a crown jewel of VBA code for inserting nested fields in a document. Using the below, I'll create a nested conditional field to display the page number on all pages excluding the first page (i.e., { IF { PAGE } = "1"""{ PAGE}}) VBA Script: Copy to clipboard Public Sub ConstructFieldsWithVBA() Dim oRng As Range Dim oFooterRng1 As Range Dim oFooterRng2 As Range Set oRng = ActiveDocument.Sections(1).Footers(wdHeaderFooterPrimary).Range With oRng .Text = "IF PAGE = ""1""""""PAGE" Set oFooterRng1 = .Duplicate Set oFooterRng2 = .Duplicate End With 'Insert the field code around the complete expression fInsertFields oFooterRng1, "IF PAGE = ""1""""""PAGE" 'Insert the field code around the Page expressions fInsertFields oFooterRng2, "PAGE" oRng.Fields.Update ActiveWindow.View.ShowFieldCodes = False lbl_Exit: Exit Sub End Sub Public Sub fInsertFields(oRng As Range, Optional strText As String) With oRng 'Find the expression and add a field around it With .Find .Text = strText .MatchCase = True While .Execute oRng.Fields.Add oRng, wdFieldEmpty, , False oRng.Collapse wdCollapseEnd Wend End With End With lbl_Exit: Exit Sub End Sub

That's it for now! I hope you have found this tips page useful and informative.  You can download a Word 2003 document containing all the code examples shown above: Field Macros.

Share

DISCLAIMER/TERMS OF USE

The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.

However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.

If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!

                                     

Search my site or the web using Google Search Engine

This page was last updated on March 09, 2021 Website Privacy StatementBack to top    Back to Word Tips



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3